package cn.itsource.hashmap;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;

/**
 *	Map：
 *		1. 概念：Map:就是用来装键值对集合的容器
 *		2. 作用：
 *				解决了需要成对出现的这种关系结构
	 *				键(key)   ： 	质就是一个数据
					值(value)   ： 	本质也是一个数据
					键值对： 就是一对（和两个是有区别的），一对一般是有某种关系
 *				例如：
 *					1、例如QQ的账号+密码：想象场景-需要使用一个集合搜集各位100人的QQ号码和密码；
					2、银行账户和密码
					3、游戏账号和密码
					4、搜集各位的姓名+女朋友的姓名 （情侣关系）
					5、坐标（x,y）
					6、....
 *		3. 
 *			Map的继承体系
			Map   接口
			  |--   HashMap   ：基于hashCode(),底层是Entry键值对的数组，数组中装装的是键值对，会根据添加的key的hashCode值 模 当前数组的length（默认是16），
			  		而得到数组的下标，进而保存键值对。如果key模length后，得到的下标是相等的，就会发生hash碰撞（哈希冲突），这时候再继续判断key的equals方法，
			  		如果equals判断为true，就会将原来的键值对覆盖，如果是false，就会在该下标处的原来键值对后面形成  链表，如果链表长度达到8个，就形成		红黑树。
			  		当删除键值对后剩余的数量小于等于6的时候，就重新将红黑树，退化为链表。（jdk1.8）put添加/remove删除
			  		
			  		key判断键是否重复和HashSet判断重复一样:1. hashCode  2.equals()
			  |		HashMap底层是Entry（键值对）的数组，并且维护了链表和红黑树
			  		
			  |--   HashTable   ： 就是一个线程安全的HashMap
			  			|--	Properties：特殊的HashTable（是HashTable子类），只不过key-value都是String类型，一般用来做
					  		配置文件：（解决硬编码问题的文件）
					  			1. .xml
					  			2. .properties
					  			3. .ini/.init
					  			4. .yml (SprintBoot)
					  			
			  |--   ConcurrentHashMap   ： 就是一个线程安全且效率更高的的HashTable，理论上是HashTable的16倍
			  |--   LinkedHashMap： 就是一个内部维护了一个链表的HashMap，可以保证存入和取出顺序
			  
 *				
			  |--   TreeMap    ： 判断key重复的规则和TreeSet一样
					TreeMap中的键（key）要么是具有自然排序能力(需要key实现Comparable接口，重写CompareTo方法)；
					或者TreeMap中提供一个比较器Comparetor实现类对象
					如果key是自然或者定制排序，返回值是0表示，key是重复的，如果是正数，则按照key的升序排序，否则是降序
					
		4. HashMap底层原理参见source文件夹中的图片	
		
		5. 遍历HashMap的三种方式：
			1. Set<Map.Entry<K,V>> entrySet() 返回所有键值对的Set集合。  
			
			2. Set<K> keySet()   返回所有键的Set集合。  
			
			3. Collection<V> values()   返回所有值的Collection集合
			
			步骤：
				1. 根据需求调用上面某一个方法，得到（键值对Entry或者键key）Set或者Collection(value)集合
				2. 遍历第一步中的Set或者Collection集合
					1. foreach
					2. 单向迭代器
					
			如果是既需要key也需要value，最好用entrySet，其他场景根据情况
			
		Map使用选择：
			1、Map中，HashMap具有超高的访问速度，如果我们只是在Map 中插入、删除和定位元素，而无关线程安全或者同步问题，HashMap 是最好的选择。
			2、如果考虑线程安全或者写入速度的话，可以使用HashTable，JDK8后建议使用ConcurrentHashMap替代HashTable,既能获取超高的访问速度，又能保证线程安全
			3、如果想按怎么存的顺序怎么取，比如队列形式，排队，那么使用LinkedHashMap
			4、如果需要让Map按照key进行升序或者降序排序，那就用TreeMap 
 */
public class HashMapForeach {

	public static void main(String[] args) {
		//这里为了方便测试，遍历Map集合，先使用泛型<>，为了避免强制转换
		HashMap<Integer,String> hashMap = new HashMap<Integer,String>();
		
		hashMap.put(1, "1");
		hashMap.put(2, "2");
		hashMap.put(3, "3");
		hashMap.put(4, "4");
		hashMap.put(5, "5");
		
		//方式1： Set<Map.Entry<K,V>> entrySet() 返回所有键值对的Set集合。  
//		Set<Entry<Integer, String>> entrySet = hashMap.entrySet();//返回所有键值对的Set集合。 
//		//遍历上面的Set集合
//		for (Entry<Integer, String> entry : entrySet) {//entry是键值对对象
//			//K getKey()获取当前键值对对应的键。  
//			Integer key = entry.getKey();
//			//V getValue()获取当前键值对对应的值。  
//			String value = entry.getValue();
//			System.out.println("键： " + key + "   值:" + value);
//		}
		
		//方式2： Set<K> keySet()   返回所有键的Set集合。  
//		Set<Integer> keySet = hashMap.keySet();
//		for (Integer key : keySet) {
//			System.out.println("key = " + key);
//			//直接通过key获取对应的value值
//			System.out.println("value = " + hashMap.get(key));
//		}
		
		//方式3：Collection<V> values()   返回所有值的Collection集合
		Collection<String> values = hashMap.values();
		for (String value : values) {
			System.out.println("值："+value);
		}
		
	}

}